package edu.cs.iit.cs495;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class WordCountJ {

	//Declare the number of threads and the arrays to store results
	public static List<String> wordResult = new ArrayList<String>();
	public static List<Integer> countResult = new ArrayList<Integer>();

	public static void main(String[] args) {
		Calendar begin, end;
		begin = Calendar.getInstance();
		int nbThread = Integer.parseInt(args[0]);
		int i , j = 0;
		int nbFile = 0;
		FileWriter out = null;
		BufferedWriter bufferWriter = null;
		File folder = null;
		File[] listOfFile = null;
		int nbInput = 0;
		FileInputStream input = null;
		DataInputStream inStream = null;
		BufferedReader bufferReader = null;

		String strLine = "";


		//Get all the file names from the folder
		folder = new File(args[1]);
		listOfFile = folder.listFiles();
		nbFile = listOfFile.length;
		List<String> listOfInput = new ArrayList<String>();
		for(i = 0; i<nbFile; i++){
			if(listOfFile[i].isFile()){
				listOfInput.add(listOfFile[i].getPath());
			}
		}
		nbInput = listOfInput.size();

		//Create a pool of threads to be handled
		ExecutorService exe = Executors.newFixedThreadPool(nbThread);
		ProcessFile p;


		for(i=0;i<nbInput;i++){
			//Open the file
			try {
				input = new FileInputStream(listOfInput.get(i));
			} catch (FileNotFoundException e2) {
				e2.printStackTrace();
			}
			inStream = new DataInputStream(input);
			bufferReader = new BufferedReader(new InputStreamReader(inStream));

			//Give each line in the file to a thread
			try {
				while ((strLine = bufferReader.readLine()) != null)   {
					p = new ProcessFile();
					p.setCountResult(countResult);
					p.setWordResult(wordResult);
					p.setStrLine(strLine);
					exe.submit(p);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

		}	
		//Wait for all the queued threads to finish
		exe.shutdown();
		try {
			//infinite timeout
			exe.awaitTermination(1, TimeUnit.DAYS);
		} catch (InterruptedException e2) {

			e2.printStackTrace();
		}




		//Output the results
		try {
			out = new FileWriter("output/result.txt");
		} catch (IOException e1) {

			e1.printStackTrace();
		}

		bufferWriter =new BufferedWriter(out);


		try {
			for( j = 0; j< wordResult.size();j++){
				bufferWriter.write(wordResult.get(j));
				bufferWriter.write("\t\t\t\t");
				bufferWriter.write(countResult.get(j).toString());
				bufferWriter.write("\n");
			}

		} catch (IOException e) {

			e.printStackTrace();
		}
		try {
			bufferWriter.close();
		} catch (IOException e) {

			e.printStackTrace();
		}
		try {
			inStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		end = Calendar.getInstance();
		//Compute running time
		long time = end.getTimeInMillis() - begin.getTimeInMillis();  
		//Print out the running time
		System.out.println("Running time : " + (float)time/(float)1000 + "sec");
		System.err.println((float)time/(float)1000);
	}	
}


class ProcessFile extends Thread{
	//path to the file processed and references to the global results
	private String strLine;
	private List<String> wordResult;
	private List<Integer> countResult;

	public ProcessFile() {
		super();
	}

	public void runFile(){
		String[] tmp = null;
		List<String> words = null;
		int count = 0;
		int index = 0;
		String currentWord = "";


		//Removes all the symbols
		strLine = strLine.replaceAll("(\\s|^)\\p{Punct}++(\\s|$)" , "$1$2");
		strLine = strLine.replaceAll("(\\w+)\\p{Punct}++(\\s|$)" , "$1$2");
		strLine = strLine.replaceAll("(\\s|^)\\p{Punct}++(\\w+)" , "$1$2");
		//Create a List of all the words in the line
		tmp = strLine.split("[^\\p{Graph}]");
		words = new ArrayList<String>();
		for(int j=0;j<tmp.length; j++ ){
			if(!tmp[j].isEmpty())
				words.add(tmp[j]);
		}

		//Count the frequency of all the words in the line and add it to the global results
		while (!words.isEmpty()) {
			currentWord = words.get(0);
			//Count the frequency of the word
			count = Collections.frequency(words,
					currentWord);

			synchronized (wordResult) {
				//Find if the word is already in the list of results	
				index = wordResult.indexOf(currentWord);

				//If not in the results yet, add it
				if (index == -1) {
					wordResult.add(currentWord);
					countResult.add(count);
				} else {
					//if already in the results, add the count to the total
					countResult.set(index, countResult.get(index)
							+ count);
				}
			}

			//Remove for the line all the words counted.
			for (int j = 0; j < words.size(); j++) {
				if (words.get(j).matches(currentWord)) {
					words.remove(j);
					j--;
				}
			}
		}
	}

	@Override
	public void run() {
		runFile();
	}

	public String getStrLine() {
		return strLine;
	}

	public void setStrLine(String strLine) {
		this.strLine= strLine;
	}
	public List<String> getWordResult() {
		return wordResult;
	}

	public void setWordResult(List<String> wordResult) {
		this.wordResult = wordResult;
	}

	public List<Integer> getCountResult() {
		return countResult;
	}

	public void setCountResult(List<Integer> countResult) {
		this.countResult = countResult;
	}

}